<cfcomponent displayname="XML Utilities" hint="I take care XML stuff" output="false">

	<cffunction  access="public" description="I take an XML document and turn it into a query." displayname="XML to Query" name="xmlToQuery" returntype="query" output="false">
		<cfargument default="<nodata><error>No data</error></nodata>" displayname="XML Document" hint="I am the XML Document" name="xmlString" type="XML" required="false">
		<cfargument default="nodata" displayname="XML path" hint="I am the path in the XML Document to the data" name="xmlPath" type="string" required="false">
		<cfset var theQuery = false />
		<cfset var temp = false />
		<cfset var xmlArray = false />
		<cfset var xmlArraySize = false />
		<cfset var lstColNames = "" />
		<cfset var xmlDataElements = "" />
		<cfset var xmlDoc = "">
		
		<!--- Check to see if the xml document passed is really an xml document --->
		<cfset xmlDoc = XmlParse(arguments.xmlString,false)>
		<cfif not isxml(xmlDoc)>
			<cfset theQuery = QueryNew("Error") >
			<cfset temp = QueryAddRow(theQuery, 1)>
			<cfset temp = QuerySetCell(theQuery, "Error","Data set contains no data! <br>Try passing a different XML Document." , 1)>
			<cfreturn theQuery>
		</cfif>
		
		<!--- Check to see if the xml path is a good path --->
		<cfset xmlArray=xmlsearch(xmlDoc,arguments.xmlPath)>
		<cfif not isArray(xmlArray) or  ArrayLen(xmlArray) is 0>
			<cfset theQuery = QueryNew("Error") >
			<cfset temp = QueryAddRow(theQuery, 1)>
			<cfset temp = QuerySetCell(theQuery, "Error","Data set contains no data! <br>Try passing a different XML Path." , 1)>
			<cfreturn theQuery>
		</cfif>
		
		<!--- Create Column header list --->
		<cfset xmlArraySize = ArrayLen(xmlArray)>
		<cfloop index="i" from = "1" to = 1>
		   	<cfset xmlDataElements = xmlArray[i].XmlChildren />
			<cfloop index="j" from="1" to="#arrayLen(xmlDataElements)#">
				<cfset lstColNames = listAppend(lstColNames,xmlDataElements[j].xmlname)>
			</cfloop>
		</cfloop>
		
		<cfset i = 0/>
		<cfset j = 0/>
		
		<!--- Create query --->
		<cfset theQuery = QueryNew("#lstColNames#") >
		<cfset temp = QueryAddRow(theQuery, #xmlArraySize#)>
		
		<cfloop index="i" from = "1" to = #xmlArraySize#>
		   	<cfset xmlDataElements = xmlArray[i].XmlChildren />
			<cfloop index="j" from="1" to="#arrayLen(xmlDataElements)#">
				<cftry>
					<cfset temp = QuerySetCell(theQuery, "#xmlDataElements[j].Xmlname#", #xmlDataElements[j].XmlText#, i)>
					<cfcatch type="any">				
					</cfcatch>
				</cftry>				
			</cfloop>
		</cfloop>
		<cfreturn theQuery>
	</cffunction>

	<cffunction name="structToXML" access="public" returntype="string">
	<cfargument default="" name="structHandle" type="struct">
	<cfargument default="allData" name="TopLevelElement" type="string">
	<cfargument default="false" name="includeXMLHeader" type="boolean">
	<cfset var fieldnames = "" />
	<cfset var output = "" />
		<cfif isStruct(structHandle)>
			 <cfif structkeyexists(structHandle,'fieldnames') >
                  <cfset fieldnames= StructFind(structHandle,'fieldnames') />
                  <cfset StructDelete(structHandle, 'fieldnames',0) />
        	</cfif>
			<cfif includeXMLHeader>
				<cfset output = "<?xml version='1.0'?><#toplevelElement#>"/>
			<cfelse>
				<cfset output = "<#toplevelElement#>" />
			</cfif>
			<cfloop collection="#structHandle#" item="strKey">
				<cfset strKey=lcase(strKey) />
				<cfset thisVal = iif(isSimpleValue(structHandle[strKey]), DE(structHandle[strKey]), DE('')) />
				<cfset safeVal = iif(find('<',thisVal,1) or find('>',thisVal,1), DE('<![CDATA[#thisVal#]]>'), DE(thisVal)) />
				<cfset output = output & "<#strKey#>#safeVal#</#strKey#>" />
			</cfloop>
			<cfset output = output & "</#toplevelElement#>" />
		</cfif>
		
		<cfreturn output/>
	</cffunction>
	
	<cffunction name="queryToXML" access="public" returntype="string">
		<cfargument name="query" type="query" required="true">
		<cfargument name="root" default="query" type="string" required="false">
		<cfargument name="nodeMode" default="values" type="string" required="false">
		<cfset var xml = xmlNew() />
		<cfset var row = "row" />
		<cfset xml.xmlRoot = xmlElemNew(xml,arguments.root) />
		<cfset xml[arguments.root].xmlAttributes["columns"] = listLen(query.columnList) />
		<cfset xml[arguments.root].xmlAttributes["rows"] = query.recordCount />
		
		<cfloop query="query">
			<cfset arrayAppend(xml[arguments.root].xmlChildren,xmlElemNew(xml,row))/>
			<cfloop list="#query.columnList#" index="idx">
				<cfswitch expression="#arguments.nodeMode#">
					<cfcase value="rows">
						<cfset xml[root][row][currentRow].xmlAttributes[idx] = query[idx][currentrow] />
					</cfcase>
					<cfcase value="columns">
						<cfset arrayAppend(xml[root][row][currentRow].xmlChildren,xmlElemNew(xml,idx)) />
						<cfset xml[root][row][currentRow][idx].xmlAttributes["value"] = query[idx][currentrow] />
					</cfcase>
					<cfdefaultcase>
						<cfset arrayAppend(xml[root][row][currentRow].xmlChildren,xmlElemNew(xml,idx)) />
						<cfif isdate(query[idx][currentrow])>
							<cfset xml[root][row][currentRow][idx].xmlText = dateformat(query[idx][currentrow],'mm/dd/yyyy') />
						<cfelse>
							<cfset xml[root][row][currentRow][idx].xmlText = query[idx][currentrow] />
						</cfif>
					</cfdefaultcase>
				</cfswitch>
			</cfloop>
		</cfloop>
		<cfreturn xml/>
	</cffunction>

</cfcomponent>